import axios from 'axios'

const API_BASE = '/api'

interface PingResult {
  ping: number
  jitter: number
}

interface ServerInfo {
  id: string
  name: string
  url: string
  country: string
  latency: number
}

class RealSpeedTestApi {
  // 可用的测试服务器列表
  private servers: ServerInfo[] = [
    { id: 'local', name: '本地服务器', url: API_BASE, country: '中国', latency: 0 },
    // 可以添加更多真实的公共测速服务器
  ]

  async testPing(onProgress?: (ping: number) => void): Promise<PingResult> {
    const tests = []
    const warmupTests = 2 // 预热测试次数
    const actualTests = 20 // 增加实际测试次数以提高准确性

    // 先进行预热测试
    for (let i = 0; i < warmupTests; i++) {
      try {
        const start = performance.now()
        await axios.get(`${API_BASE}/ping`, {
          timeout: 3000,
          headers: { 'Cache-Control': 'no-cache' }
        })
        await new Promise(resolve => setTimeout(resolve, 100))
      } catch (error) {
        // 预热测试失败忽略
      }
    }

    // 进行实际的ping测试
    for (let i = 0; i < actualTests; i++) {
      const start = performance.now()

      try {
        await axios.get(`${API_BASE}/ping`, {
          timeout: 5000,
          headers: { 'Cache-Control': 'no-cache' }
        })

        const end = performance.now()
        const pingValue = end - start
        tests.push(pingValue)

        // 实时回调
        if (onProgress) {
          onProgress(pingValue)
        }
      } catch (error) {
        console.error(`Ping test ${i + 1} failed:`, error)
        throw new Error(`Ping测试失败: ${(error as Error).message}`)
      }

      // 测试间隔
      if (i < actualTests - 1) {
        await new Promise(resolve => setTimeout(resolve, 50)) // 减小间隔以增加测试密度
      }
    }

    if (tests.length === 0) {
      throw new Error('Ping测试全部失败')
    }

    // 去掉最高和最低值以减少异常值影响
    tests.sort((a, b) => a - b)
    const filteredTests = tests.slice(2, tests.length - 2) // 去掉更多异常值

    if (filteredTests.length === 0) {
      throw new Error('没有有效的Ping测试结果')
    }

    const avgPing = filteredTests.reduce((a, b) => a + b, 0) / filteredTests.length
    
    // 标准网络抖动计算方法：计算相邻ping值的差异的平均值
    let jitterSum = 0
    for (let i = 1; i < filteredTests.length; i++) {
      jitterSum += Math.abs(filteredTests[i] - filteredTests[i - 1])
    }
    const jitter = jitterSum / (filteredTests.length - 1)

    return {
      ping: Math.max(avgPing, 1),
      jitter: Math.max(jitter, 0.1)
    }
  }

  async testDownloadSpeed(onProgress?: (speed: number) => void): Promise<number> {
    // 智能调整线程数和测试数据大小
    const deviceScore = this.calculateDeviceScore()
    const threadCount = this.determineOptimalThreadCount(deviceScore)
    const testSizes = this.determineOptimalTestSizes(deviceScore)
    
    let totalSpeed = 0
    let successfulTests = 0
    let totalDownloadedBytes = 0
    let totalDuration = 0

    // 预热阶段
    try {
      await this.warmupDownload()
    } catch (error) {
      console.warn('Download warmup failed:', error)
    }

    // 使用多线程下载测试，但改进同步和计算方式
    for (let sizeIndex = 0; sizeIndex < testSizes.length; sizeIndex++) {
      const size = testSizes[sizeIndex]
      const threadResults: Array<{speed: number, bytes: number, duration: number}> = []
      const startTime = performance.now()

      try {
        // 启动多个并发下载线程
        const threadPromises = []

        for (let t = 0; t < threadCount; t++) {
          const threadPromise = this.downloadThread(size, threadCount, t)
          threadPromises.push(threadPromise)
        }

        // 等待所有线程完成
        const results = await Promise.allSettled(threadPromises)
        
        // 处理成功的线程结果
        results.forEach((result, index) => {
          if (result.status === 'fulfilled') {
            const {speed, bytes, duration} = result.value
            threadResults.push({speed, bytes, duration})
            console.debug(`Thread ${index + 1}: ${speed.toFixed(2)} Mbps, ${(bytes/1024/1024).toFixed(2)} MB, ${duration.toFixed(2)}s`)
          } else {
            console.error(`Download thread ${index + 1} failed:`, result.reason)
          }
        })

        const endTime = performance.now()
        const testDuration = (endTime - startTime) / 1000

        if (threadResults.length === 0) {
          throw new Error('所有下载线程都失败了')
        }

        // 计算总下载量和总速度 - 使用更精确的方法
        const testDownloadedBytes = threadResults.reduce((sum, result) => sum + result.bytes, 0)
        const testAvgSpeed = (testDownloadedBytes * 8) / (testDuration * 1024 * 1024) // Mbps
        
        // 累加总统计数据
        totalDownloadedBytes += testDownloadedBytes
        totalDuration += testDuration
        totalSpeed += testAvgSpeed
        successfulTests++
        
        // 计算加权平均速度，更准确反映实际下载性能
        const weightedAverageSpeed = (totalDownloadedBytes * 8) / (totalDuration * 1024 * 1024)

        if (onProgress) {
          onProgress(weightedAverageSpeed)
        }

        await new Promise(resolve => setTimeout(resolve, 100))

        // 如果速度已经稳定，可以提前结束测试
        if (sizeIndex > 1 && successfulTests > 1) {
          const prevAverage = (totalSpeed - testAvgSpeed) / (successfulTests - 1)
          const stability = Math.abs(testAvgSpeed - prevAverage) / prevAverage
          
          if (stability < 0.05) { // 稳定性在5%以内
            console.log(`Download speed stabilized (${stability.toFixed(4)}), ending test early`)
            break
          }
        }

      } catch (error) {
        console.error(`Download test ${sizeIndex + 1} failed:`, error)
        // 继续下一个测试而不是直接break
        continue
      }
    }

    if (successfulTests === 0) {
      throw new Error('下载测试全部失败')
    }

    // 返回加权平均速度，这更能反映真实下载性能
    const finalWeightedSpeed = (totalDownloadedBytes * 8) / (totalDuration * 1024 * 1024)
    return Math.max(finalWeightedSpeed, 0.1)
  }

  // 单个下载线程的实现 - 改进版本
  private async downloadThread(
      totalSize: number,
      totalThreads: number,
      threadIndex: number
  ): Promise<{speed: number, bytes: number, duration: number}> {
    const threadSize = Math.ceil(totalSize / totalThreads)
    const start = performance.now()

    try {
      // 增强防缓存措施
      const uniqueUrl = `${API_BASE}/download/${threadSize}?thread=${threadIndex}&t=${Date.now()}&random=${Math.random().toString(36).substr(2, 9)}`

      // 使用更底层的fetch API以获得更精确的控制
      const controller = new AbortController()
      const timeoutId = setTimeout(() => controller.abort(), 60000) // 60秒超时

      const response = await fetch(uniqueUrl, { method: 'GET',
        headers: {
          'Cache-Control': 'no-cache, no-store, must-revalidate',
          'Pragma': 'no-cache',
          'Expires': '0'
        },
        signal: controller.signal,
        credentials: 'same-origin'
      })

      clearTimeout(timeoutId)

      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`)
      }

      // 读取响应体以确保完全下载
      const blob = await response.blob()
      const end = performance.now()
      
      const duration = (end - start) / 1000
      const actualSize = blob.size
      const speed = (actualSize * 8) / (duration * 1024 * 1024) // Mbps

      // 立即释放blob资源
      URL.revokeObjectURL(URL.createObjectURL(blob))

      return { speed, bytes: actualSize, duration }

    } catch (error) {
      console.error(`Download thread ${threadIndex + 1} failed:`, error)
      throw new Error(`下载线程失败: ${(error as Error).message}`)
    }
  }
  
  // 计算设备性能分数，用于优化测试参数
  private calculateDeviceScore(): number {
    // 基础分数
    let score = 50
    
    // 根据CPU核心数调整
    const cores = navigator.hardwareConcurrency || 4
    score += Math.min(cores * 5, 30)
    
    // 根据内存估计调整
    const memory = navigator.deviceMemory || 4
    score += Math.min(memory * 3, 15)
    
    // 根据网络类型调整
    if (navigator.connection) {
      const downlink = navigator.connection.downlink || 1
      score += Math.min(downlink * 2, 5)
    }
    
    return score
  }
  
  // 根据设备性能确定最佳线程数
  private determineOptimalThreadCount(deviceScore: number): number {
    // 低性能设备: 1-2线程
    if (deviceScore < 70) return 2
    // 中等性能设备: 3-4线程
    if (deviceScore < 90) return 4
    // 高性能设备: 5-6线程
    return Math.min(6, navigator.hardwareConcurrency || 4)
  }
  
  // 根据设备性能确定最佳测试数据大小
  private determineOptimalTestSizes(deviceScore: number): number[] {
    // 低性能设备或慢网络: 使用较小的测试数据
    if (deviceScore < 70) return [2, 5, 10] // MB
    // 中等性能设备: 标准测试数据
    if (deviceScore < 90) return [5, 10, 20] // MB
    // 高性能设备或快网络: 较大的测试数据以获得更准确的结果
    return [10, 20, 50] // MB
  }
  
  async testUploadSpeed(onProgress?: (speed: number) => void): Promise<number> {
    // 使用更多的测试数据和更精确的计时
    const testSizes = [5, 10, 15] // MB，增大测试数据量
    let totalSpeed = 0
    let successfulTests = 0
    let totalUploadedBytes = 0
    let totalDuration = 0

    // 预热阶段
    try {
      await this.warmupUpload()
    } catch (error) {
      console.warn('Upload warmup failed:', error)
    }

    for (let i = 0; i < testSizes.length; i++) {
      const size = testSizes[i]
      // 创建真实的、不可压缩的随机数据
      const data = this.generateRandomData(size)
      const formData = new FormData()
      formData.append('file', data, `test-data-${size}-${Date.now()}.bin`)

      const start = performance.now()
      let lastProgressUpdate = 0

      try {
        // 使用axios的onUploadProgress回调获取准确的上传字节数
        const response = await axios.post(`${API_BASE}/upload`, formData, {
          timeout: 60000, // 延长超时时间
          headers: {
            'Content-Type': 'multipart/form-data',
            'Cache-Control': 'no-cache'
          },
          onUploadProgress: (progressEvent) => {
            if (progressEvent.total && progressEvent.loaded) {
              const current = performance.now()
              const duration = (current - start) / 1000
              const uploadedBytes = progressEvent.loaded
              const currentSpeed = (uploadedBytes * 8) / (duration * 1024 * 1024) // Mbps

              // 限制进度更新频率以避免性能问题
              if (onProgress && duration > 0.1 && current - lastProgressUpdate > 100) {
                onProgress(currentSpeed)
                lastProgressUpdate = current
              }
            }
          }
        })

        const end = performance.now()
        const duration = (end - start) / 1000
        
        // 从响应中获取实际上传的字节数（如果服务器返回）
        let actualUploadedBytes = data.size
        if (response.headers && response.headers['x-uploaded-bytes']) {
          actualUploadedBytes = parseInt(response.headers['x-uploaded-bytes'], 10)
        }
        
        // 使用实际上传的字节数计算速度，而不是预定义的size
        const speed = (actualUploadedBytes * 8) / (duration * 1024 * 1024) // Mbps

        // 累加总统计数据
        totalUploadedBytes += actualUploadedBytes
        totalDuration += duration
        totalSpeed += speed
        successfulTests++
        
        // 计算加权平均速度
        const weightedAverageSpeed = (totalUploadedBytes * 8) / (totalDuration * 1024 * 1024)

        if (onProgress) {
          onProgress(weightedAverageSpeed)
        }

        await new Promise(resolve => setTimeout(resolve, 100))

        // 如果速度已经稳定，可以提前结束测试
        if (i > 1 && successfulTests > 1) {
          const prevAverage = (totalSpeed - speed) / (successfulTests - 1)
          const stability = Math.abs(speed - prevAverage) / prevAverage
          
          if (stability < 0.1) { // 稳定性在10%以内
            console.log('Upload speed stabilized, ending test early')
            break
          }
        }

      } catch (error) {
        console.error(`Upload test ${i + 1} failed:`, error)
        // 继续下一个测试而不是直接break
        continue
      }
    }

    if (successfulTests === 0) {
      throw new Error('上传测试全部失败')
    }

    // 返回加权平均速度，更准确反映真实上传性能
    const finalWeightedSpeed = (totalUploadedBytes * 8) / (totalDuration * 1024 * 1024)
    return Math.max(finalWeightedSpeed, 0.1)
  }



  // 生成真正的随机、不可压缩的数据
  private generateRandomData(sizeMB: number): Blob {
    const sizeBytes = sizeMB * 1024 * 1024
    const arrayBuffer = new ArrayBuffer(sizeBytes)
    const uint8Array = new Uint8Array(arrayBuffer)

    // 使用crypto API生成高质量的随机数据
    if (typeof window.crypto !== 'undefined' && window.crypto.getRandomValues) {
      // 分批生成随机数据，避免内存问题
      const batchSize = 65536 // 64KB
      for (let i = 0; i < uint8Array.length; i += batchSize) {
        const batchLength = Math.min(batchSize, uint8Array.length - i)
        const batch = uint8Array.subarray(i, i + batchLength)
        window.crypto.getRandomValues(batch)
      }
    } else {
      // 降级方案
      for (let i = 0; i < uint8Array.length; i++) {
        uint8Array[i] = Math.floor(Math.random() * 256)
      }
    }

    return new Blob([arrayBuffer])
  }

  // 下载预热，减少第一次请求的影响
  private async warmupDownload(): Promise<void> {
    try {
      const response = await axios.get(`${API_BASE}/download/1?warmup=true`, {
        responseType: 'blob',
        timeout: 5000,
        headers: { 'Cache-Control': 'no-cache' }
      })
      // 确保数据被完全读取
      await response.data.arrayBuffer()
    } catch (error) {
      throw error
    }
  }

  // 上传预热
  private async warmupUpload(): Promise<void> {
    try {
      const smallData = new Blob(['warmup data'])
      const formData = new FormData()
      formData.append('file', smallData, 'warmup.bin')

      await axios.post(`${API_BASE}/upload?warmup=true`, formData, {
        timeout: 5000,
        headers: {
          'Content-Type': 'multipart/form-data',
          'Cache-Control': 'no-cache'
        }
      })
    } catch (error) {
      throw error
    }
  }

  // 获取可用的测试服务器
  async getAvailableServers(): Promise<ServerInfo[]> {
    // 在实际应用中，这里可能会从服务器获取真实的服务器列表
    return this.servers
  }
}

export const realSpeedTestApi = new RealSpeedTestApi()